<template>
  <div @keydown.30.stop="beginStop" @keydown.37="changeDirection(37)" @keydown.38="changeDirection(38)"
       @keydown.39="changeDirection(39)" @keydown.40="changeDirection(40)">
    贪吃蛇
    <h4>分数:{{ nowScore }}</h4>
    <button @click="goBack">返回目录</button>
    <table align="center">
      <tr v-for="row in grids" :key="row.index">
        <td v-for="grid in row" :style="{'background-color':grid==0?'#ffffff':(grid==1?'#260c0c':'#ec1010')}"
            :key="grid.index"></td>
      </tr>
    </table>
    <button @click="createNets()">新一局</button>
    <button @click="beginStop()">{{ move == null ? "开始" : "暂停" }}</button>
    区块大小:<select v-model="rangeId" @change="changeRange()">
    <option value="0">25x50</option>
    <option value="1">50x80</option>
    <option value="2">80x150</option>
  </select>
    速度:<select v-model="speed" @change="changeSpeed()" ref="speedSelect">
    <option value="1">1x</option>
    <option value="2">2x</option>
    <option value="3">3x</option>
  </select>
    <div align="center">
      <div class="controlBlock" @click="changeDirection(38)">上</div>
      <div class="controlBlock" style="display: inline-block" @click="changeDirection(37)">左</div>
      <div class="controlBlock" style="display: inline-block" @click="beginStop()">{{ move == null ? "|>" : "||" }}</div>
      <div class="controlBlock" style="display: inline-block" @click="changeDirection(39)">右</div>
      <div class="controlBlock" @click="changeDirection(40)">下</div>
    </div>
  </div>
</template>

<script>
export default {
  data() {
    return {
      direction: [0, 1],//移动方向
      rowSize: 50,
      columnSize: 80,
      grids: [], //所有格子状态的集合
      snake: [], //蛇坐标集合
      foodPoint: null, //食物点坐标
      blanks: [], //空白坐标集合
      rangeId: 1,//区块大小ID
      oldRangeId: 1,//区块更改前ID
      move: null, //移动事件
      nowScore: 0,//目前分数
      speed: 2//速度
    }
  },
  methods: {
    //返回目录
    goBack() {
      window.history.back()
    },
    //创建二维元素组，存放各个表格状态
    createNets() {
      this.grids = [];
      this.snake = [];
      this.blanks = [];
      this.direction = [0, 1];
      this.foodPoint = null;
      this.nowScore = 0;
      this.speed = 2;
      for (let rowIndex = 0; rowIndex < this.rowSize; rowIndex++) {
        let row = [];
        for (let columnIndex = 0; columnIndex < this.columnSize; columnIndex++) {
          let grid = 0; //0代表空，1代表蛇，2代表食物
          if (rowIndex == Math.round(this.rowSize / 2) && columnIndex > Math.round(this.columnSize / 2 - 5) && columnIndex <= Math.round(this.columnSize / 2)) {
            grid = 1;
            this.snake.push([rowIndex, columnIndex]);
          } else {
            this.blanks.push([rowIndex, columnIndex]);
          }
          row.push(grid);
        }
        this.grids.push(row);
      }
      this.freshFood();
    },
    //刷新食物点
    freshFood() {
      if (this.blanks.length == 0) {
        clearInterval(this.move);
        this.move = null;
        alert("胜利");
        return false;
      }
      const index = Math.round(Math.random() * this.blanks.length);
      this.foodPoint = this.blanks[index];
      this.grids[this.foodPoint[0]][this.foodPoint[1]] = 2;
      this.blanks.splice(index, 1);
      return true;
    },
    //蛇移动
    snakeMove() {
      const lastSnakePoint = this.snake[0];
      const firstSnakePoint = this.snake[this.snake.length - 1];
      const newSnakePoint = [firstSnakePoint[0] + this.direction[0], firstSnakePoint[1] + this.direction[1]];
      //如果下一个移动点是蛇本身则移动失败
      if (this.snake.some((item, index) => {
        if (item[0] == newSnakePoint[0] && item[1] == newSnakePoint[1]) {
          return true;
        }
      })) {
        clearInterval(this.move);
        this.move = null;
        alert("吃自己");
        return false;
      }
      //如果下一个移动点是墙壁则移动失败
      if (newSnakePoint[0] < 0 || newSnakePoint[1] < 0 || newSnakePoint[0] >= this.rowSize || newSnakePoint[1] >=
        this.columnSize) {
        alert("碰墙璧");
        clearInterval(this.move);
        this.move = null;
        return false;
      }
      this.snake.push(newSnakePoint);
      this.grids[newSnakePoint[0]][newSnakePoint[1]] = 1;
      //删除空白点
      this.blanks.some((item, index) => {
        if (item[0] == newSnakePoint[0] && item[1] == newSnakePoint[1]) {
          this.blanks.splice(index, 1);
          this.$forceUpdate();
          return true;
        }
      })
      //如果下一移动点是食物则增加蛇的记录点，并刷新食物点
      if (newSnakePoint[0] == this.foodPoint[0] && newSnakePoint[1] == this.foodPoint[1]) {
        this.nowScore = this.nowScore + this.speed * 50;
        this.freshFood();
      } else {
        //其他情况则移出蛇的随后一个点
        this.snake.splice(0, 1);
        this.grids[lastSnakePoint[0]][lastSnakePoint[1]] = 0;
        this.blanks.push(lastSnakePoint);
      }
      this.$forceUpdate();
      return true;
    },
    //开始暂停游戏
    beginStop() {
      if (this.move == null) {
        this.move = setInterval(this.snakeMove, 200 / this.speed);
      } else {
        clearInterval(this.move);
        this.move = null;
      }
    },
    //改变区域大小
    changeRange() {
      if (this.snake.length > 5) {
        if (!confirm("重新开始本局游戏么？")) {
          this.rangeId = this.oldRangeId;
          return;
        }
      }
      if (this.rangeId == 0) {
        this.rowSize = 25;
        this.columnSize = 50;
        this.oldRangeId = 0;
      }
      if (this.rangeId == 1) {
        this.rowSize = 50;
        this.columnSize = 80;
        this.oldRangeId = 1;
      }
      if (this.rangeId == 2) {
        this.rowSize = 80;
        this.columnSize = 150;
        this.oldRangeId = 2;
      }
      this.createNets();
      this.$forceUpdate();
    },
    //改变速度大小
    changeSpeed() {
      if (this.move != null) {
        clearInterval(this.move);
        this.move = setInterval(this.snakeMove, 200 / this.speed);
        this.$refs["speedSelect"].blur();
      }
    },
    //根据键位改变方向
    changeDirection(val) {
      if (val == 37) {
        if (this.direction[0] != 0 && this.direction[1] != 1) {
          this.direction = [0, -1];
        }
      } else if (val == 38) {
        if (this.direction[0] != 1 && this.direction[1] != 0) {
          this.direction = [-1, 0];
        }
      } else if (val == 39) {
        if (this.direction[0] != 0 && this.direction[1] != -1) {
          this.direction = [0, 1];
        }
      } else if (val == 40) {
        if (this.direction[0] != -1 && this.direction[1] != 0) {
          this.direction = [1, 0];
        }
      }
    }
  },
  created() {
    this.createNets();
  }
}
</script>

<style>
td {
  width: 4px;
}

tr {
  height: 5px;
}

table {
  border-width: 2px;
  border-style: solid;
  border-collapse: collapse;
  border-spacing: 0;
}

.controlBlock{
  background: antiquewhite;
  width: 100Px;
  height: 100px;
  text-align: center;
  line-height:100px;
  font-size: 80px;
  margin: 10px 10px;
}
</style>
